package com.share.config.filter.log;

import com.alibaba.fastjson.JSON;
import com.share.common.utils.DbUtil;
import com.share.common.utils.MdcUtil;
import com.share.common.utils.ThreadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.Optional;

/**
 * @calssName LogFilter
 * @Description 全局日志打印, 请求日志以及返回日志, 并在返回结果日志中添加请求时间
 * @Order表示这个bean的注入初始化的顺序 Ordered 是同一个接口的执行顺序
 */
@Slf4j
@Component
@WebFilter("/**")
public class LogFilter implements Filter {

    @Autowired
    private Environment env;

    @Resource
    private DataSource dataSource;

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        MdcUtil.initTraceId();

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        // 获取请求信息
        AccessLog accessLog = createAccessLog(request, response);
        String reqContentType = servletRequest.getContentType();
        reqContentType = reqContentType == null ? "" : reqContentType;

        // post请求body体的数据读取
        if ("POST".equals(accessLog.getMethod())) {
            if (reqContentType.contains("json") || reqContentType.contains("form")) {
                //json请求的百度都是答案
                LogReadRequestWrapper jsonWrapper = new LogReadRequestWrapper(request);
                String str = jsonWrapper.getBody() == null ? null : new String(jsonWrapper.getBody());
                accessLog.setRequest(str);
                request = jsonWrapper;
            }
        } else if ("GET".equals(accessLog.getMethod())) {
            //form格式的
            accessLog.setRequest(request.getQueryString());
        }

        //响应处理
        LogReadResponeWrapper responeWrapper = new LogReadResponeWrapper((HttpServletResponse) servletResponse);
        response = responeWrapper;


        filterChain.doFilter(request, response);

        //输出数据
        String resp = wirteOrginRespone(servletResponse, responeWrapper);

        //保存日志
        accessLog.setContentType(reqContentType);//格式
        accessLog.setEndTime(System.currentTimeMillis());//结束时间
        accessLog.setResponse(resp);//结果
        accessLog.setCostTime(accessLog.getEndTime() - accessLog.getStartTime());
        ThreadUtil.execute(() -> DbUtil.saveAccessLog(dataSource, (Map<String, Object>) JSON.toJSON(accessLog)));
    }

    private String wirteOrginRespone(ServletResponse servletResponse, LogReadResponeWrapper responeWrapper) throws IOException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String resContentType = responeWrapper.getContentType();
        resContentType = resContentType == null ? "" : resContentType;

        //读取缓存
        responeWrapper.flushBuffer();
        byte[] resp = responeWrapper.getBody();

        //输出数据
        response.setLocale(responeWrapper.getLocale());
        response.setBufferSize(responeWrapper.getBufferSize());
        response.setStatus(responeWrapper.getStatus());
        response.setContentType(resContentType);
        response.getOutputStream().write(resp);

        if (resContentType.contains("json")) {
            return resp == null ? null : new String(resp);
        } else {
            return "数据非json格式";
        }
    }


    //参数构建对象
    private AccessLog createAccessLog(HttpServletRequest request, HttpServletResponse response) {
        // 获取请求信息
        AccessLog accessLog = new AccessLog();
        accessLog.setService(env.getProperty("spring.application.name"));//服务名字
        accessLog.setStartTime(System.currentTimeMillis());//开始时间

        String method = request.getMethod();
        accessLog.setMethod(method);//method

        //ip地址
        String ip = request.getHeader("X-Forwarded-For");
        ip = Optional.ofNullable(ip).orElse(request.getHeader("X-Real-IP"));
        ip = Optional.ofNullable(ip).orElse(request.getRemoteAddr());
        accessLog.setIp(ip);//host

        //请求地址
        String uri = null;
        String contextPath = request.getContextPath();
        if (contextPath.length() > 1) {
            String requestURI = request.getRequestURI();
            int i = requestURI.indexOf(contextPath);
            uri = requestURI.substring(i + contextPath.length());
        } else {
            uri = request.getRequestURI();
        }
        accessLog.setUri(uri);

        //提取请求参数
        String param = null;
        if (!"POST".contains(method)) {
            param = request.getQueryString();//地址后面的参数,post请求也可以携带
        }
        accessLog.setRequest(param);
        accessLog.setCreateTime(new Date());

        return accessLog;
    }
}
